{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The String Widgets\n",
    "\n",
    "+ HTMLWidget\n",
    "+ LatexWidget\n",
    "+ TextWidget\n",
    "+ TextArea"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets are used to display data conventionally represented as strings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "{-# LANGUAGE OverloadedStrings #-}\n",
    "{-# LANGUAGE FlexibleContexts #-}\n",    
    "import IHaskell.Display.Widgets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- Constructors\n",
    "html <- mkHTMLWidget\n",
    "latex <- mkLatexWidget\n",
    "text <- mkTextWidget\n",
    "area <- mkTextArea"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets have a `Text` payload, represented by the `StringValue` field."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### HTML and Latex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `HTMLWidget` and `LatexWidget` display `Text` as rich formatted *HTML* and *LaTeX* respectively."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "-- Display the widgets\n",
    "html\n",
    "latex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- Set some html string\n",
    "setField html StringValue \"<b>Bold</b>\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- Set some latex string\n",
    "setField latex StringValue \"$x + y$\"\n",
    "\n",
    "-- The default width of LatexWidget is somewhat small\n",
    "setField latex Width 400"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also add some padding to the widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "setField html Padding 10\n",
    "setField latex Padding 10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  `TextWidget` and `TextArea`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's see what they look like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "text\n",
    "area"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "-- Some padding\n",
    "setField text Padding 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `TextWidget` and `TextArea` also have a `Placeholder` property, which represents the text displayed in empty widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "setField text Placeholder \"Enter your text here...\"\n",
    "setField area Placeholder \"Parsed output will appear here...\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Both the widgets also accept input. The `StringValue` of the widget is automatically updated on every change to the widget. Additionally, the `TextWidget` also has a `SubmitHandler` which is triggered on hitting the return/enter key."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below we set up the `TextWidget` and `TextArea` for parsing phone numbers using parsec. The `TextWidget` is used to recieve input, and the `TextArea` is used to display output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "-- Import parsec and other required libraries\n",
    "\n",
    "import Text.Parsec\n",
    "import Text.Parsec.String\n",
    "import Data.Text (pack, unpack)\n",
    "import Control.Applicative ((<$>))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we can write some parsers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "-- Parse a single digit\n",
    "digit :: Parser Char\n",
    "digit = oneOf ['0'..'9']\n",
    "\n",
    "-- Parse a multi-digit number.\n",
    "number :: Parser Integer\n",
    "number = do\n",
    "  digits <- many1 digit -- At least one digit\n",
    "  return (read digits)  -- Convert [Char] to Integer\n",
    "  \n",
    "-- Parse a country code, starting with a +.\n",
    "countryCode :: Parser Integer\n",
    "countryCode = do\n",
    "  char '+'\n",
    "  number\n",
    "  \n",
    "-- Parse an area code, optionally with parentheses.\n",
    "areaCode :: Parser Integer\n",
    "areaCode = choice [withParens, withoutParens]\n",
    "  where\n",
    "    withParens = between (char '(') (char ')') withoutParens\n",
    "    withoutParens = number\n",
    "  \n",
    "-- Simple data type representing a phone number.\n",
    "-- Real phone numbers are much more complex!\n",
    "data PhoneNumber = PhoneNumber {\n",
    "    phoneCountryCode :: Maybe Integer,\n",
    "    phoneNumbers :: [Integer]\n",
    "  } deriving (Eq, Show)\n",
    "  \n",
    "phoneNumber :: Parser PhoneNumber\n",
    "phoneNumber = do\n",
    "  -- Try to parse a country code. If it doesn't work, it's Nothing.\n",
    "  c <- optionMaybe countryCode\n",
    "  optional separator\n",
    "  a1 <- areaCode\n",
    "  separator -- Separator required after area code\n",
    "  a2 <- number\n",
    "  separator -- Separator required before last group of digits\n",
    "  a3 <- number\n",
    "  return (PhoneNumber c [a1, a2, a3])\n",
    "  \n",
    "  where\n",
    "    separator = oneOf \" -\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we set the `TextWidget`'s change handler to parse the input, and write the output to the `TextArea`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "setField text ChangeHandler $ do\n",
    "  input <- unpack <$> getField text StringValue\n",
    "  str <- case parse phoneNumber \"<text widget>\" input of\n",
    "             Left error -> return (show error)\n",
    "             Right x -> return (show x)\n",
    "  setField area StringValue (pack str)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `TextArea` doesn't have a `SubmitHandler`, but does have a `ChangeHandler`. It is best used to display large amounts of text."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can re-display the widgets (nobody likes to scroll needlessly):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "text\n",
    "area"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Haskell",
   "language": "haskell",
   "name": "haskell"
  },
  "language_info": {
   "codemirror_mode": "ihaskell",
   "file_extension": ".hs",
   "name": "haskell",
   "version": "7.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
